/**
 * 
 */
package com.carnation.qa.socketserver.common.util;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.carnation.qa.socketserver.domain.Item;

/**
 * @author Nick
 * 
 */
public class Comparer {

	/**
	 * 忽略当前行内容标记
	 */
	public static final String TAG_IGNORE_THIS = "?";

	/**
	 * 忽略当前行及所有下级内容标记
	 */
	public static final String TAG_IGNORE_ALL = "*";

	private final Log log = LogFactory.getLog(getClass());

	private boolean isDifference = false;

	public boolean diff(final String expectedString, final String outString) {
		if (log.isDebugEnabled()) {
			log.debug("Expected:" + expectedString + ",Out:" + outString);
		}
		TreeParser parser = new TreeParser();
		List<Item> expectedList = parser.parseTree(expectedString);
		List<Item> outList = parser.parseTree(outString);
		if (expectedList.isEmpty() && outList.isEmpty()) {
			return false;
		}
		if (expectedList.isEmpty() || outList.isEmpty()) {
			return true;
		}
		return diff(expectedList, outList);
	}

	private boolean diff(final List<Item> expectedList, final List<Item> outList) {
		Item expected = expectedList.get(0);
		Item out = outList.get(0);
		if (log.isDebugEnabled()) {
			log.debug("Expected:" + expected.toString() + "\r\nOut:"
					+ out.toString());
		}
		compare(expected, out);
		return isDifference;
	}

	private void compare(final Item expectedItem, final Item outItem) {
		if (isDifference) {
			return;
		}
		boolean needCompareChildren = true;

		if (expectedItem.getLabel().equals(outItem.getLabel())) {
			// 行相同比较下级节点
		} else {
			String[] expectedParts = expectedItem.getLabelParts();
			String[] outParts = outItem.getLabelParts();
			if (expectedParts[0].equals(outParts[0])) {
				if (expectedParts[1].equals(outParts[1])) {
					// 相同
				} else if (expectedParts[1].equals(TAG_IGNORE_THIS)) {
					// 忽略当前行
				} else if (expectedParts[1].equals(TAG_IGNORE_ALL)) {
					// 忽略当前行及子项内容
					needCompareChildren = false;
				} else {
					// 值不同
					if (log.isDebugEnabled()) {
						log.debug("Line:" + (expectedItem.getLineNumber() + 1)
								+ ",Expected<: " + expectedParts[1]
								+ " >,Out:< " + outParts[1] + " >");
					}
					isDifference = true;
				}
			} else {
				if (log.isDebugEnabled()) {
					log.debug("Line:" + (expectedItem.getLineNumber() + 1)
							+ ",Expected<: " + expectedParts[0] + " >,Out:< "
							+ outParts[0] + " >");
				}
				isDifference = true;
			}
		}
		if (needCompareChildren) {
			Map<Integer, Item> mapOut = new HashMap<Integer, Item>();
			for (Item i : outItem.getChildren()) {
				mapOut.put(toHashCode(i), i);
			}
			for (Item i : expectedItem.getChildren()) {
				int hashCode = toHashCode(i);
				if (mapOut.containsKey(hashCode)) {
					compare(i, mapOut.get(hashCode));
				} else {
					// 期望值未存在
					if (log.isDebugEnabled()) {
						log.debug("Line:" + (i.getLineNumber() + 1)
								+ ",Unexisted Expection<: " + i.getLabel()
								+ " >");
					}
					isDifference = true;
				}
			}
		}

	}

	private int toHashCode(Item item) {
		return item.getLabelParts()[0].hashCode();
	}
}
